#ifndef _unittest_h_
#define _unittest_h_

#include <string>
#include <vector>
#include <iostream>

#include <time.h>

namespace simple_test{
    // UnitTestFunction is the base class for all unit test
    // functions. The macros defined at the bottom of this file will
    // construct objects derived from UnitTestFunction.
    //
    // When you write a unit test function, it executes as a member
    // or an object derived from apUnitTestFunction.  Useful 
    // functions:
    //
    //   VERIFY(condition)       A macro wrapped around verify(). If
    //                           condition resolves to false, the
    //                           unit test will fail.
    //   verifyFloat (d1,d2);    Verifies that d1= d2, within a
    //                           small value delta.  If this 
    //                           condition is false, the unit test 
    //                           will fail.
    //   VERIFYFLOAT(d1,d2);     Same as verifyFlot() to match the
    //                           look of VERIFY().
    //   addMessage (string);    Adds the string to our internal
    //                           message string.
    //
    // You should call VERIFY() or VERIFYFLOAT() at least once in 
    // each unit test function.  If you don't the result state of
    // the function will be eUnknown.
    class UnitTestFunction
    {
    public:
        UnitTestFunction (const std::string& name);

        enum eResult {eNotRun, eRunning, eUnknown, eSuccess, eFailure};
        // Each unit test has a result, even if the user never sets it

        const std::string& name         () const { return _name;}
        eResult            result       () const { return _result;}
        double             elapsed      () const { return _elapsed;}
        const std::string& message      () const { return _message;}
        const std::string& description  () const { return _description;}
        std::string        resultString () const;

        void setDescription (const std::string& s) { _description = s;}
        // Set the description of this test function

        void run (bool detail = false);
        // Run this unit test. Called by the unit test framework


    protected:
        virtual void test() = 0;
        // All unit tests define this function to perform a single test

        bool verify (bool state, const std::string& message="");
        // Fails test if state is false. Used by VERIFY() macro

        bool verifyFloat (double d1, double d2);
        // Verifies d1=d2, within a value delta. Used by VERIFYFLOAT()

        void addMessage (const std::string& message);
        // Adds the message string to our messages

        bool         _detail;     // true for detail output

        eResult      _result;      // Result of this unit test
        std::string  _name;        // Unit test name (must be unique)
        std::string  _description; // Description of function
        std::string  _message;     // Message, usual a failure message
        double       _elapsed;     // Execution time, in seconds
    };

    class UnitTest
    {
    public:
        static UnitTest& gOnly ();
        // The only instance of this object we create

        bool run (bool detail = false);
        // Run all the unit tests. Returns true if all tests are ok

        void dumpResults (std::ostream& out);
        // Dump results to specified stream

        int size () const { return static_cast<int>(_tests.size());}

        const UnitTestFunction* find (int index) const;
        // Finds the specific test, or NULL if invalid index

        void addTest (const std::string& name, UnitTestFunction* test);
        // Used by our macro to add another unit test

    private:
        UnitTest ();  // We will only have one instance, gOnly()

        static UnitTest* _sOnly;  // Points to our only instance

        std::vector<UnitTestFunction*> _tests;   // Array of tests
        time_t _start, _stop;                    // Start, stop time
    };

    // This might look difficult, but它创建了一个唯一的
    // 继承自UnitTestFunction的类。A static instance is also
    // created which will add itself to the array of unit tests in
    // the UnitTest object (there is only a single, global
    // instance of UnitTest created). When the unit tests are run,
    // the test() method of each derived object is called. An 
    // example unit test function (which always passed) is show 
    // below: 
    //
    //    UTFUNC(test)
    //    {
    //      VERIFY (true);
    //    }
    //
    // The ## is the merging operator.  a##b = ab
    // The # is a stringization operator  #a = "a"

    #define UTFUNC(utx)                            \
    class UT##utx : public UnitTestFunction        \
    {                                              \
        UT##utx ();                                \
        static UT##utx sInstance;                  \
        void test ();                              \
    };                                             \
    UT##utx UT##utx::sInstance;                    \
    UT##utx::UT##utx () : UnitTestFunction(#utx)   \
    {                                              \
        UnitTest::gOnly().addTest(#utx,this);      \
    }                                              \
    void UT##utx::test ()
    // 这样,在一个实现的UTFUNC(xx){}大括号，正好衔接着test ()，成为test()的函数体。

    #define VERIFY(condition) verify (condition, #condition)
    #define VERIFYFLOAT(d1,d2) verifyFloat (d1, d2)
}

#endif // _unittest_h_
